package com.yc.testupload.controller;

import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.MultipartConfig;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.Part;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.math.BigDecimal;
import java.security.MessageDigest;
import java.io.FileInputStream;
import java.io.BufferedInputStream;
import com.yc.testupload.util.DatabaseUtil;
import com.yc.testupload.util.EnvironmentManager;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.UUID;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Properties;

// 七牛云相关导入
import com.qiniu.storage.UploadManager;
import com.qiniu.util.Auth;
import com.qiniu.http.Response;
import com.qiniu.common.QiniuException;
import com.qiniu.common.Zone;
import com.qiniu.storage.Configuration;

// 文档信息类，用于存储重复文档信息
class DocumentInfo {
    private int id;
    private String title;

    public DocumentInfo(int id, String title) {
        this.id = id;
        this.title = title;
    }

    public int getId() {
        return id;
    }

    public String getTitle() {
        return title;
    }
}

@WebServlet(name = "fileUploadServlet", value = "/upload")
@MultipartConfig(fileSizeThreshold = 1024 * 1024, // 1MB
        maxFileSize = 50 * 1024 * 1024, // 50MB
        maxRequestSize = 55 * 1024 * 1024 // 55MB
)
public class FileUploadServlet extends HttpServlet {

    // 日志记录器
    private static final Logger logger = LogManager.getLogger(FileUploadServlet.class);

    // 图片解析API的基本URL
    private String analyzeApiBase;
    // 本地文件保存路径
    private String uploadPath;
    // 当前运行环境
    private String env;

    // 七牛云配置
    private static final String ACCESS_KEY = "vV_FGopUcLpPKwImUgDE8a2lCgTQjsdUqQmSpoa1";
    private static final String SECRET_KEY = "w94IZ6dV899KrEqofAFwkagn0SSeZPPEXgaTj3Jr";
    private static final String BUCKET_NAME = "project-yytimes";
    private static final String DOMAIN = "static.didaproject.com";

    @Override
    public void init() throws ServletException {
        super.init();

        // 从环境配置中获取图片解析API的基本URL
        try {
            // 获取当前环境
            String currentEnv = EnvironmentManager.getInstance().getCurrentEnvironment();
            // 获取当前环境的配置
            Properties config = EnvironmentManager.getInstance().getDatabaseConfig(currentEnv);

            // 获取图片分析API配置，如果没有则使用默认值
            String imageAnalysisApi = config.getProperty("image.analysis.api",
                    "http://127.0.0.1:50001/tasks/");

            // 确保URL格式正确
            if (!imageAnalysisApi.endsWith("/")) {
                imageAnalysisApi += "/";
            }

            // 提取主机名和端口，构建正确的API路径
            URL url = new URL(imageAnalysisApi);
            analyzeApiBase = "http://" + url.getHost() + ":" + url.getPort() + "/tasks/";

            logger.info("初始化图片解析API基础URL: {}", analyzeApiBase);
        } catch (Exception e) {
            // 初始化失败时使用默认值
            analyzeApiBase = "http://127.0.0.1:50001/tasks/";
            logger.error("初始化图片解析API配置失败，使用默认值: {}", e.getMessage());
        }

        // 从环境管理器获取当前环境配置
        // 当动态切换正式环境时为上线环境，切换测试环境时为测试环境
        this.env = EnvironmentManager.getInstance().getCurrentEnvironment();
        logger.info("获取当前环境配置: {}", this.env);

        if (EnvironmentManager.ENVIRONMENT_PROD.equals(this.env) || EnvironmentManager.ENVIRONMENT_TEST.equals(this.env)
                || true) {
            // 所有环境（包括正式环境）：使用与测试环境相同的路径逻辑
            // 尝试获取webapp目录
            String webappPath = getServletContext().getRealPath("/");

            // 如果getRealPath返回null（例如在独立JAR运行模式下），使用当前工作目录
            if (webappPath == null) {
                webappPath = System.getProperty("user.dir") + File.separator;
            }

            // 确保webappPath以分隔符结尾
            if (!webappPath.endsWith(File.separator)) {
                webappPath += File.separator;
            }

            // 线下环境：使用项目内的uploads目录
            // 线上环境：使用正式环境路径
            if (EnvironmentManager.ENVIRONMENT_PROD.equals(this.env)) {
                uploadPath = "/www/wwwroot/doc.didaproject.com/public/uploads/file/";
                logger.info("正式环境 - 设置Linux兼容文件上传路径: {}", uploadPath);
            } else {
                // 线下环境使用项目内的uploads目录
                uploadPath = webappPath + "uploads" + File.separator + "file" + File.separator;
                logger.info("测试/开发环境 - 设置项目内上传路径: {}", uploadPath);
            }
            
            // 修正路径：确保移除任何可能出现的jar目录
            if (uploadPath.contains("jar/")) {
                uploadPath = uploadPath.replace("jar/", "");
                logger.info("修正上传路径，移除多余的jar目录: {}", uploadPath);
            } else if (uploadPath.contains("jar\\")) {
                uploadPath = uploadPath.replace("jar\\", "");
                logger.info("修正上传路径，移除多余的jar目录: {}", uploadPath);
            }
        }

        // 创建目录
        File uploadDir = new File(uploadPath);
        if (!uploadDir.exists()) {
            boolean created = uploadDir.mkdirs();
            if (!created) {
                logger.error("无法创建上传目录: " + uploadPath);
                throw new ServletException("无法创建上传目录: " + uploadPath);
            } else {
                logger.info("成功创建上传目录: " + uploadPath);
            }
        } else {
            logger.debug("上传目录已存在: " + uploadPath);
        }
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        request.setCharacterEncoding("UTF-8");
        response.setContentType("application/json;charset=utf-8");

        PrintWriter out = response.getWriter();
        String resultJson = "";

        Connection conn = null;
        PreparedStatement pstmt = null;

        // 在方法开始处定义wenId变量，确保整个方法都能访问
        int wenId = 0;

        // 移除提交时的重复标题检查逻辑，让文件能够正常上传
        // 前端将在选择文件时进行重复标题检查和弹窗提示

        try {
            // 获取表单字段值
            String title = request.getParameter("title") != null ? request.getParameter("title") : "";
            String category = request.getParameter("category") != null ? request.getParameter("category") : "";
            logger.info("category: {}", category);
            String documentType = request.getParameter("documentType") != null ? request.getParameter("documentType")
                    : "free";
            // 统一使用'pay'作为付费文档类型
            if ("paid".equals(documentType)) {
                documentType = "pay";
            }

            // 限制documentType长度，避免数据库字段数据截断
            if (documentType != null && documentType.length() > 10) {
                documentType = documentType.substring(0, 10);
                logger.warn("文档类型过长，已截断为: {}", documentType);
            }
            String price = request.getParameter("price") != null ? request.getParameter("price") : "";

            String fileName = null;
            String savedFilePath = null;
            String newFileName = null;

            // 获取上传的文件
            Collection<Part> parts = request.getParts();
            for (Part part : parts) {
                // 检查是否是文件部分
                if (part.getContentType() != null && part.getSubmittedFileName() != null
                        && !part.getSubmittedFileName().isEmpty()) {
                    // 获取原始文件名
                    fileName = part.getSubmittedFileName();

                    // 生成唯一文件名，避免覆盖
                    String uuid = UUID.randomUUID().toString().replaceAll("-", "");
                    String suffixName = fileName.substring(fileName.lastIndexOf("."));
                    newFileName = uuid + suffixName;

                    // 动态生成当天日期目录
                    SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd");
                    String dateDir = dateFormat.format(new Date());

                    // 构建文件保存路径，根据操作系统使用正确的路径分隔符
                    String separator = File.separator;
                    savedFilePath = uploadPath + dateDir + separator + newFileName;
                    
                    // 再次修正最终保存路径，确保移除任何可能出现的jar目录
                    if (savedFilePath.contains("jar/")) {
                        savedFilePath = savedFilePath.replace("jar/", "");
                        logger.info("修正最终保存路径，移除多余的jar目录: {}", savedFilePath);
                    } else if (savedFilePath.contains("jar\\")) {
                        savedFilePath = savedFilePath.replace("jar\\", "");
                        logger.info("修正最终保存路径，移除多余的jar目录: {}", savedFilePath);
                    }

                    // 在Windows系统上，确保路径格式正确
                    if (File.separatorChar == '\\') {
                        savedFilePath = savedFilePath.replace('/', '\\');
                    }

                    // 保存文件前先检查并确保目录存在
                    try {
                        // 获取文件的父目录
                        File parentDir = new File(savedFilePath).getParentFile();
                        boolean directoryCreated = false;
                        // 检查目录是否存在，如果不存在则创建
                        if (parentDir != null && !parentDir.exists()) {
                            // 尝试创建目录
                            directoryCreated = parentDir.mkdirs();
                            logger.info("尝试创建保存目录: {}, 创建结果: {}", parentDir.getAbsolutePath(), directoryCreated);

                            // 再次检查目录是否存在，确保创建成功
                            if (!parentDir.exists()) {
                                logger.error("创建保存目录失败: {}, 即使mkdirs()返回: {}", parentDir.getAbsolutePath(),
                                        directoryCreated);
                                resultJson = String.format("{\"code\":1,\"message\":\"文件上传失败，无法创建保存目录: %s\"}",
                                        parentDir.getAbsolutePath());
                                out.write(resultJson);
                                out.flush();
                                return;
                            }
                        }
                        logger.info("保存目录已确认存在: {}", parentDir != null ? parentDir.getAbsolutePath() : "N/A");

                        // 统一的文件保存逻辑，所有环境使用相同的保存方式
                        // 再次确认目录存在，确保在不同环境下都能正常创建目录
                        File saveFile = new File(savedFilePath);
                        File dir = saveFile.getParentFile();
                        if (dir != null && !dir.exists()) {
                            boolean dirCreated = dir.mkdirs();
                            logger.info("再次创建目录结果: {}, 目录路径: {}", dirCreated, dir.getAbsolutePath());

                            // 强制检查目录是否存在，即使mkdirs()返回true
                            if (!dir.exists()) {
                                logger.error("再次创建目录失败，即使mkdirs()返回: {}", dirCreated);
                                resultJson = String.format("{\"code\":1,\"message\":\"文件上传失败，目录创建失败: %s\"}",
                                        dir.getAbsolutePath());
                                out.write(resultJson);
                                out.flush();
                                return;
                            }
                        }

                        part.write(savedFilePath);
                        logger.info("{}环境 - 文件已保存: {}",
                                (EnvironmentManager.ENVIRONMENT_PROD.equals(this.env) ? "正式"
                                        : (EnvironmentManager.ENVIRONMENT_TEST.equals(this.env) ? "测试" : "默认")),
                                savedFilePath);

                        // 验证文件是否成功保存到本地
                        File savedFile = new File(savedFilePath);
                        if (!savedFile.exists() || !savedFile.isFile() || savedFile.length() == 0) {
                            String errorDetails = String.format("文件验证失败 - 路径: %s, 存在: %s, 是文件: %s, 文件大小: %s字节",
                                    savedFilePath, savedFile.exists(), savedFile.isFile(),
                                    savedFile.exists() ? savedFile.length() : "N/A");
                            logger.error("文件保存到本地失败或文件为空: {}", errorDetails);
                            resultJson = String.format("{\"code\":1,\"message\":\"文件上传失败，保存文件到本地失败: %s\"}",
                                    errorDetails);
                            out.write(resultJson);
                            out.flush();
                            return;
                        }
                        logger.info("文件已成功保存到本地并验证通过: {}, 文件大小: {}字节", savedFilePath, savedFile.length());
                    } catch (Exception e) {
                        // 打印完整的异常堆栈信息
                        logger.error("保存文件失败: {}, 详细信息: ", e.getMessage(), e);
                        String errorDetails = String.format("保存路径: %s, 异常类型: %s, 异常消息: %s",
                                savedFilePath, e.getClass().getName(), e.getMessage());
                        resultJson = String.format("{\"code\":1,\"message\":\"文件上传失败，保存文件时出错: %s\"}", errorDetails);
                        out.write(resultJson);
                        out.flush();
                        return;
                    }
                }
            }

            // 检查必要参数
            if (fileName == null || fileName.isEmpty() || savedFilePath == null) {
                resultJson = "{\"code\":1,\"message\":\"文件上传失败，未接收到文件\"}";
            } else {
                // 如果用户没有提供标题，自动使用文件名（去除扩展名）作为标题
                if (title.isEmpty() && fileName != null && fileName.lastIndexOf(".") > 0) {
                    title = fileName.substring(0, fileName.lastIndexOf("."));
                    logger.info("自动生成标题: {}", title);
                }

                // 默认设置成功响应
                resultJson = "{\"code\":0,\"message\":\"上传成功\",\"data\":{\"fileName\":\"" + fileName
                        + "\",\"documentType\":\"" + documentType + "\"";

                // 如果是付费文档，添加价格信息
                if ("paid".equals(documentType)) {
                    resultJson += ",\"price\":\"" + price + "\"";
                }

                resultJson += "}}";

                // 记录上传的文档信息到日志
                logger.info("文档上传成功: 标题={}, 分类={}, 类型={}, 文件名={}",
                        title, category, documentType, fileName);

                // 保存文档信息到数据库
                try {
                    conn = DatabaseUtil.getConnection();
                    if (conn != null) {
                        // 先保存文件信息到wk_file表
                        String fileSql = "INSERT INTO wk_file (file_md5, file_url, ben_file, file_name, file_size, file_ext, user_id) VALUES (?, ?, ?, ?, ?, ?, ?)";

                        // 计算文件MD5
                        String fileMd5 = calculateFileMD5(savedFilePath);

                        // 获取文件信息
                        File file = new File(savedFilePath);
                        long fileSize = file.length();
                        String fileExt = newFileName.substring(newFileName.lastIndexOf(".") + 1);

                        // 使用当前日期创建目录路径
                        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd");
                        String dateDir = dateFormat.format(new Date());

                        // 上传文件到七牛云
                        String qiniuUrl = uploadToQiniuCloud(savedFilePath, newFileName);

                        // 使用七牛云URL作为fileUrl
                        String fileUrl = qiniuUrl != null ? qiniuUrl : "/uploads/file/" + dateDir + "/" + newFileName;
                        // benFile保持不变，始终使用本地URL格式
                        String benFile = "/uploads/file/" + dateDir + "/" + newFileName;

                        // 使用title作为文件名主体，保留原文件扩展名
                        String titleBasedFileName = title + "." + fileExt;

                        // 记录wk_file表SQL语句到日志，将?替换为实际参数值
                        String fileSqlWithParams = String.format(
                                "INSERT INTO wk_file (file_md5, file_url, ben_file, file_name, file_size, file_ext, user_id) VALUES ('%s', '%s', '%s', '%s', %d, '%s', %d)",
                                fileMd5.replace("'", "''"), // 转义单引号
                                fileUrl.replace("'", "''"), // 转义单引号
                                benFile.replace("'", "''"), // 转义单引号
                                titleBasedFileName.replace("'", "''"), // 转义单引号
                                fileSize,
                                fileExt.replace("'", "''"), // 转义单引号
                                1); // 用户ID，假设为1
                        logger.info("准备执行wk_file表插入SQL: {}", fileSqlWithParams);

                        // 执行wk_file表插入并获取自动生成的file_id
                        pstmt = conn.prepareStatement(fileSql, PreparedStatement.RETURN_GENERATED_KEYS);
                        pstmt.setString(1, fileMd5);
                        pstmt.setString(2, fileUrl);
                        pstmt.setString(3, benFile);
                        pstmt.setString(4, titleBasedFileName);
                        pstmt.setLong(5, fileSize);
                        pstmt.setString(6, fileExt);
                        // 从会话中获取当前登录用户的user_id
                        Integer userId = (Integer) request.getSession().getAttribute("userId");
                        if (userId == null) {
                            userId = 0; // 默认值，确保SQL不会出错
                        }
                        pstmt.setInt(7, userId);

                        int fileRowsAffected = pstmt.executeUpdate();
                        logger.info("文件信息已保存到wk_file表，影响行数: {}", fileRowsAffected);

                        // 获取自动生成的file_id
                        int fileId = 1; // 默认值
                        try (java.sql.ResultSet generatedKeys = pstmt.getGeneratedKeys()) {
                            if (generatedKeys.next()) {
                                fileId = generatedKeys.getInt(1);
                                logger.info("file_id: {}", fileId);
                            }
                        }

                        // 关闭pstmt，准备插入wk_wenku表
                        try {
                            pstmt.close();
                        } catch (SQLException e) {
                            logger.error("关闭PreparedStatement失败", e);
                        }

                        // 插入文档信息到wk_wenku表
                        String wenkuSql = "INSERT INTO wk_wenku (title, user_id, wen_type, file_id, file_jine, type_id, add_time, edit_time, status) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)";

                        // 设置参数
                        BigDecimal priceValue = BigDecimal.ZERO;
                        if ("pay".equals(documentType) && !price.isEmpty()) {
                            try {
                                priceValue = new BigDecimal(price);
                            } catch (NumberFormatException e) {
                                priceValue = BigDecimal.ZERO;
                            }
                        }

                        // 从前端获取分类ID
                        int typeId = 0;
                        if (!category.isEmpty()) {
                            try {
                                // 直接将前端传递的category参数转换为整数作为typeId
                                typeId = Integer.parseInt(category);
                                logger.debug("从前端获取的分类ID: {}", typeId);
                            } catch (NumberFormatException e) {
                                // 如果转换失败，使用默认值
                                typeId = 1;
                                logger.warn("分类ID格式错误，使用默认值: {}, 错误信息: {}", typeId, e.getMessage());
                            }
                        } else {
                            // 如果没有传递分类参数，使用默认值
                            typeId = 1;
                            logger.debug("未传递分类参数，使用默认值: {}", typeId);
                        }

                        // 设置时间戳，使用当前时间的秒数（数据库需要秒级时间戳）
                        long currentTime = System.currentTimeMillis() / 1000;

                        // 记录SQL语句到日志，将?替换为实际参数值
                        String sqlWithParams = String.format(
                                "INSERT INTO wk_wenku (title, user_id, wen_type, file_id, file_jine, type_id, add_time, edit_time, status) VALUES ('%s', %d, '%s', %d, %s, %d, %d, %d, %d)",
                                title.replace("'", "''"), // 转义单引号
                                1,
                                documentType.replace("'", "''"), // 转义单引号
                                fileId,
                                priceValue,
                                typeId,
                                currentTime,
                                currentTime,
                                0);
                        logger.info("准备执行wk_wenku表插入SQL: {}", sqlWithParams);

                        pstmt = conn.prepareStatement(wenkuSql, PreparedStatement.RETURN_GENERATED_KEYS);
                        pstmt.setString(1, title); // 文档标题
                        pstmt.setInt(2, userId); // 用户ID
                        pstmt.setString(3, documentType); // 文档类型(vip/pay/free)
                        pstmt.setInt(4, fileId); // 文件ID
                        pstmt.setBigDecimal(5, priceValue);
                        pstmt.setInt(6, typeId);
                        pstmt.setLong(7, currentTime); // 添加时间
                        pstmt.setLong(8, currentTime); // 编辑时间
                        pstmt.setInt(9, 1); // 状态为0（正常）

                        int wenkuRowsAffected = pstmt.executeUpdate();
                        logger.info("文档信息已保存到wk_wenku表，影响行数: {}", wenkuRowsAffected);

                        // 获取自动生成的wen_id
                        try (java.sql.ResultSet generatedKeys = pstmt.getGeneratedKeys()) {
                            if (generatedKeys.next()) {
                                wenId = generatedKeys.getInt(1);
                                logger.info("wen_id: {}", wenId);
                            }
                        }

                    }
                } catch (SQLException e) {
                    logger.error("保存文件信息到数据库失败: {}", e.getMessage());
                    // 数据库操作失败不应影响文件上传的成功状态
                } finally {
                    if (pstmt != null) {
                        try {
                            pstmt.close();
                        } catch (SQLException e) {
                            logger.error("关闭PreparedStatement失败", e);
                        }
                    }
                    if (conn != null) {
                        DatabaseUtil.closeConnection(conn);
                    }
                }

                // 数据库操作完成后，将文件上传到七牛云
                String qiniuUrl = uploadToQiniuCloud(savedFilePath, newFileName);

                // if (qiniuUrl != null) {
                // logger.info("文件已成功上传到七牛云，开始保存到素材表");
                // // 将七牛云URL保存到素材表
                // // saveToMaterialTable(title, qiniuUrl, category, title, new
                // SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
                // } else {
                // logger.warn("文件上传到七牛云失败，无法保存到素材表");
                // }

                // 调用图片解析接口
                String analyzeResult = callImageAnalyzeApi(savedFilePath, newFileName, wenId);

                // 根据API返回结果记录日志，但不影响已设置的响应
                if (analyzeResult != null && (analyzeResult.contains("success") || analyzeResult.contains("OK"))) {
                    logger.info("图片解析API调用成功: {}", analyzeResult);
                } else {
                    logger.warn("图片解析API调用失败: {}", analyzeResult);
                }
            }
        } catch (Exception e) {
            resultJson = "{\"code\":4,\"message\":\"服务器内部错误\"}";
            logger.error("服务器内部错误", e);
        } finally {
            try {
                out.write(resultJson);
                out.flush();
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                if (out != null) {
                    try {
                        out.close();
                    } catch (Exception e) {
                        logger.error("关闭响应输出流异常", e);
                    }
                }
            }
        }
    }

    /**
     * 计算文件的MD5值
     */
    private String calculateFileMD5(String filePath) {
        try {
            MessageDigest md = MessageDigest.getInstance("MD5");
            FileInputStream fis = new FileInputStream(filePath);
            BufferedInputStream bis = new BufferedInputStream(fis);
            byte[] buffer = new byte[8192];
            int bytesRead;

            while ((bytesRead = bis.read(buffer)) != -1) {
                md.update(buffer, 0, bytesRead);
            }

            bis.close();
            fis.close();

            byte[] md5Bytes = md.digest();
            StringBuilder sb = new StringBuilder();
            for (byte b : md5Bytes) {
                sb.append(String.format("%02x", b));
            }

            return sb.toString();
        } catch (Exception e) {
            logger.error("计算文件MD5失败: {}", e.getMessage());
            return "";
        }
    }

    /**
     * 将文件上传到七牛云
     */
    private String uploadToQiniuCloud(String filePath, String fileName) {
        String qiniuUrl = null;

        try {
            // 构建七牛云配置，使用Zone.autoZone自动选择最优区域
            Configuration cfg = new Configuration(Zone.autoZone());

            // 创建上传管理器
            UploadManager uploadManager = new UploadManager(cfg);

            // 获取文件扩展名
            String fileExt = fileName.substring(fileName.lastIndexOf("."));

            // 生成时间戳加随机字符串的文件名，符合用户要求的格式
            long timestamp = System.currentTimeMillis();
            String randomStr = UUID.randomUUID().toString().replaceAll("-", "").substring(0, 10);
            String newFileName = timestamp + randomStr + fileExt;

            // 构建七牛云中的文件路径，使用wenku前缀
            String key = "wenku/" + newFileName;

            // 生成上传凭证
            Auth auth = Auth.create(ACCESS_KEY, SECRET_KEY);
            String upToken = auth.uploadToken(BUCKET_NAME, key);

            // 上传文件
            Response response = uploadManager.put(filePath, key, upToken);

            // 构建文件的访问URL
            qiniuUrl = "https://" + DOMAIN + "/" + key;

            logger.info("文件已成功上传到七牛云，URL: {}", qiniuUrl);
        } catch (QiniuException e) {
            logger.error("上传文件到七牛云失败: {}", e.getMessage());
            // 可以获取响应信息
            if (e.response != null) {
                logger.error("七牛云错误响应: {}", e.response.toString());
            }
        } catch (Exception e) {
            logger.error("上传文件到七牛云时发生异常: {}", e.getMessage());
        }

        return qiniuUrl;
    }

    /**
     * 调用图片解析API
     */
    private String callImageAnalyzeApi(String filePath, String newFileName, int wenId) {
        try {
            // 在每次调用时获取最新的图片解析API配置
            String currentAnalyzeApiBase = getLatestImageAnalyzeApiBase();

            // 构建API请求参数
            // 注意：这里需要将本地文件路径转换为接口需要的URL格式
            // 接口要求的格式：http://testdoc2.didaproject.com:50001/tasks/?left_url=_@_www_@_wwwroot_@_testdoc2.didaproject.com_@_public_@_uploads_@_file_@_20250917_@_425966a3-be2c-472e-8a39-cc6c4c02d72d.pdf&wen_id=5823&mode=1

            // 构建left_url参数值，确保在所有环境下都使用统一的_@_home_@_gep_@_app_@_uploads_@_格式
            String leftUrl;
            SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd");
            String dateDir = dateFormat.format(new Date());
            leftUrl = "_@_www_@_wwwroot_@_doc.didaproject.com_@_public_@_uploads_@_file_@_" + dateDir + "_@_"
                    + newFileName;
            logger.info("构建的left_url: {}", leftUrl);

            // 构建完整的API URL，使用动态的文档ID和动态获取的API基础URL
            String apiUrl = currentAnalyzeApiBase + "?left_url=" + leftUrl + "&wen_id=" + wenId + "&mode=1";

            logger.info("调用图片解析API: " + apiUrl);

            // 创建URL连接
            URL url = new URL(apiUrl);
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            conn.setRequestMethod("GET");
            conn.setConnectTimeout(5000);
            conn.setReadTimeout(10000);

            // 获取响应
            StringBuilder response = new StringBuilder();
            try (BufferedReader reader = new BufferedReader(
                    new InputStreamReader(conn.getInputStream(), StandardCharsets.UTF_8))) {
                String line;
                while ((line = reader.readLine()) != null) {
                    response.append(line);
                }
            }

            conn.disconnect();

            logger.debug("API响应: " + response.toString());
            return response.toString();
        } catch (Exception e) {
            // 在开发环境中，API调用可能会失败，返回模拟成功结果
            logger.warn("无法连接到图片解析API，可能是开发环境，返回模拟结果: " + e.getMessage());
            // 返回一个包含success关键字的模拟成功结果
            return "模拟解析成功 {success: true}";
        }
    }

    /**
     * 获取最新的图片解析API基础URL
     * 每次调用时都会从环境配置中获取最新的配置
     */
    private String getLatestImageAnalyzeApiBase() {
        try {
            // 获取当前环境
            String currentEnv = EnvironmentManager.getInstance().getCurrentEnvironment();
            logger.info("当前环境: {}", currentEnv);

            // 从环境配置中获取图片解析API的URL
            // 使用与配置文件中一致的键名image.analysis.api
            Properties config = EnvironmentManager.getInstance().getCurrentDatabaseConfig();
            String apiBase = config.getProperty("image.analysis.api", "http://127.0.0.1:50000");

            // 确保URL包含/tasks/路径
            if (!apiBase.endsWith("/tasks/")) {
                if (apiBase.endsWith("/")) {
                    apiBase += "tasks/";
                } else {
                    apiBase += "/tasks/";
                }
            }

            logger.info("从环境配置获取图片解析API基础URL: {}", apiBase);
            return apiBase;
        } catch (Exception e) {
            // 获取失败时使用默认值
            logger.error("获取图片解析API配置失败，使用默认值: {}", e.getMessage());
            String defaultApiBase = "http://127.0.0.1:50001/tasks/";
            logger.info("异常情况下使用默认图片解析API基础URL: {}", defaultApiBase);
            return defaultApiBase;
        }
    }

    /**
     * 将内容保存到素材表
     */
    private int saveToMaterialTable(String title, String content, String category, String sourceUrl,
            String currentTime) {
        logger.info("开始将内容保存到素材表: {}", title);
        long startTime = System.currentTimeMillis();
        int materialId = -1;
        Connection conn = null;
        PreparedStatement pstmt = null;

        try {
            // 获取数据库连接
            conn = DatabaseUtil.getConnection();
            logger.info("已获取数据库连接");

            // 保存到wk_material表
            String sql = "INSERT INTO wk_material (title, content, category_id, user_id, source_url, add_time, edit_time, status) VALUES (?, ?, ?, ?, ?, ?, ?, ?)";
            pstmt = conn.prepareStatement(sql, PreparedStatement.RETURN_GENERATED_KEYS);
            pstmt.setString(1, title);
            pstmt.setString(2, content); // 这里content是七牛云URL
            pstmt.setInt(3, 31); // 分类ID，使用默认值31
            pstmt.setInt(4, 1); // 用户ID，假设为1
            pstmt.setString(5, sourceUrl);
            // 使用Unix时间戳格式，避免日期格式不匹配问题
            pstmt.setLong(6, System.currentTimeMillis() / 1000); // add_time
            pstmt.setLong(7, System.currentTimeMillis() / 1000); // edit_time
            pstmt.setInt(8, 1); // status，设为1（可用）

            int rowsAffected = pstmt.executeUpdate();
            logger.info("执行SQL语句影响的行数: {}", rowsAffected);

            // 获取生成的素材ID
            if (rowsAffected > 0) {
                try (java.sql.ResultSet rs = pstmt.getGeneratedKeys()) {
                    if (rs.next()) {
                        materialId = rs.getInt(1);
                        logger.info("成功保存到素材表，素材ID: {}", materialId);
                    }
                }
            }

        } catch (SQLException e) {
            logger.error("保存到素材表失败: {}", e.getMessage(), e);
        } finally {
            // 关闭数据库资源
            if (pstmt != null) {
                try {
                    pstmt.close();
                } catch (SQLException e) {
                    logger.error("关闭PreparedStatement失败", e);
                }
            }
            DatabaseUtil.closeConnection(conn);
        }

        long endTime = System.currentTimeMillis();
        logger.info("素材表操作完成，耗时: {} ms", (endTime - startTime));
        return materialId;
    }

    /**
     * 检查是否存在相同标题的文档
     */
    private List<DocumentInfo> checkForDuplicateTitles(Connection conn, String title) throws SQLException {
        List<DocumentInfo> duplicates = new ArrayList<>();
        PreparedStatement pstmt = null;
        ResultSet rs = null;

        try {
            // 查询与给定标题相同的文档，排除当前正在上传的文档
            String sql = "SELECT id, title FROM wk_wenku WHERE title = ? AND id != ?";
            pstmt = conn.prepareStatement(sql);
            pstmt.setString(1, title);
            pstmt.setInt(2, 0); // 0表示不存在的文档ID，确保不会排除任何现有文档

            rs = pstmt.executeQuery();
            while (rs.next()) {
                int id = rs.getInt("id");
                String docTitle = rs.getString("title");
                duplicates.add(new DocumentInfo(id, docTitle));
            }
        } finally {
            if (rs != null) {
                try {
                    rs.close();
                } catch (SQLException e) {
                    logger.error("关闭ResultSet失败", e);
                }
            }
            if (pstmt != null) {
                try {
                    pstmt.close();
                } catch (SQLException e) {
                    logger.error("关闭PreparedStatement失败", e);
                }
            }
        }

        return duplicates;
    }

    /**
     * 转义JSON字符串中的特殊字符
     */
    private String escapeJson(String text) {
        if (text == null) {
            return "";
        }
        return text.replace("\"", "\\\"").replace("\\", "\\\\").replace("\n", "\\n").replace("\r", "\\r");
    }

    /**
     * 公共的文件上传方法，供其他类调用
     * 包含保存文件、上传到七牛云以及调用图片解析API的完整流程
     * 
     * @param file 要上传的文件对象
     * @param title 文档标题
     * @param category 分类ID
     * @param documentType 文档类型(free/pay)
     * @param price 价格（付费文档时使用）
     * @param userId 用户ID
     * @return 包含上传结果的JSON字符串
     */
    public String uploadFile(File file, String title, String category, String documentType, String price, int userId) {
        logger.info("开始调用公共文件上传方法: title={}, category={}, documentType={}", title, category, documentType);
        
        String resultJson = ""; 
        Connection conn = null;
        PreparedStatement pstmt = null;
        int wenId = 0; // 文档ID
        
        try {
            // 1. 准备文件保存相关信息
            String fileName = file.getName();
            String uuid = UUID.randomUUID().toString().replaceAll("-", "");
            String suffixName = fileName.substring(fileName.lastIndexOf("."));
            String newFileName = uuid + suffixName;
            
            // 动态生成当天日期目录
            SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd");
            String dateDir = dateFormat.format(new Date());
            
            // 构建文件保存路径
            String separator = File.separator;
            String savedFilePath = uploadPath + dateDir + separator + newFileName;
            
            // 在Windows系统上，确保路径格式正确
            if (File.separatorChar == '\\') {
                savedFilePath = savedFilePath.replace('/', '\\');
            }
            
            // 2. 确保目录存在
            File parentDir = new File(savedFilePath).getParentFile();
            if (parentDir != null && !parentDir.exists()) {
                boolean dirCreated = parentDir.mkdirs();
                logger.info("创建保存目录: {}, 结果: {}", parentDir.getAbsolutePath(), dirCreated);
                
                if (!parentDir.exists()) {
                    return String.format("{\"code\":1,\"message\":\"文件上传失败，无法创建保存目录\"}");
                }
            }
            
            // 3. 保存文件
            java.nio.file.Files.copy(file.toPath(), new File(savedFilePath).toPath(), java.nio.file.StandardCopyOption.REPLACE_EXISTING);
            logger.info("文件已保存到: {}", savedFilePath);
            
            // 验证文件是否成功保存
            File savedFile = new File(savedFilePath);
            if (!savedFile.exists() || !savedFile.isFile() || savedFile.length() == 0) {
                String errorDetails = String.format("文件验证失败 - 路径: %s, 存在: %s, 是文件: %s, 文件大小: %s字节",
                        savedFilePath, savedFile.exists(), savedFile.isFile(),
                        savedFile.exists() ? savedFile.length() : "N/A");
                logger.error(errorDetails);
                return String.format("{\"code\":1,\"message\":\"文件上传失败，保存文件到本地失败\"}");
            }
            
            // 4. 保存文件信息到数据库
            try {
                conn = DatabaseUtil.getConnection();
                if (conn != null) {
                    // 计算文件MD5
                    String fileMd5 = calculateFileMD5(savedFilePath);
                    
                    // 获取文件信息
                    long fileSize = file.length();
                    String fileExt = newFileName.substring(newFileName.lastIndexOf(".") + 1);
                    
                    // 上传文件到七牛云
                    String qiniuUrl = uploadToQiniuCloud(savedFilePath, newFileName);
                    
                    // 构建文件URL
                    String fileUrl = qiniuUrl != null ? qiniuUrl : "/uploads/file/" + dateDir + "/" + newFileName;
                    String benFile = "/uploads/file/" + dateDir + "/" + newFileName;
                    
                    // 使用title作为文件名主体
                    String titleBasedFileName = title + "." + fileExt;
                    
                    // 插入wk_file表
                    String fileSql = "INSERT INTO wk_file (file_md5, file_url, ben_file, file_name, file_size, file_ext, user_id) VALUES (?, ?, ?, ?, ?, ?, ?)";
                    pstmt = conn.prepareStatement(fileSql, PreparedStatement.RETURN_GENERATED_KEYS);
                    pstmt.setString(1, fileMd5);
                    pstmt.setString(2, fileUrl);
                    pstmt.setString(3, benFile);
                    pstmt.setString(4, titleBasedFileName);
                    pstmt.setLong(5, fileSize);
                    pstmt.setString(6, fileExt);
                    pstmt.setInt(7, userId);
                    
                    int fileRowsAffected = pstmt.executeUpdate();
                    logger.info("文件信息已保存到wk_file表，影响行数: {}", fileRowsAffected);
                    
                    // 获取file_id
                    int fileId = 1;
                    try (java.sql.ResultSet generatedKeys = pstmt.getGeneratedKeys()) {
                        if (generatedKeys.next()) {
                            fileId = generatedKeys.getInt(1);
                        }
                    }
                    
                    // 关闭pstmt
                    pstmt.close();
                    
                    // 插入wk_wenku表
                    String wenkuSql = "INSERT INTO wk_wenku (title, user_id, wen_type, file_id, file_jine, type_id, add_time, edit_time, status) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)";
                    
                    // 设置价格
                    BigDecimal priceValue = BigDecimal.ZERO;
                    if ("pay".equals(documentType) && !price.isEmpty()) {
                        try {
                            priceValue = new BigDecimal(price);
                        } catch (NumberFormatException e) {
                            priceValue = BigDecimal.ZERO;
                        }
                    }
                    
                    // 设置分类ID
                    int typeId = 1;
                    if (!category.isEmpty()) {
                        try {
                            typeId = Integer.parseInt(category);
                        } catch (NumberFormatException e) {
                            typeId = 1;
                        }
                    }
                    
                    // 设置时间戳
                    long currentTime = System.currentTimeMillis() / 1000;
                    
                    pstmt = conn.prepareStatement(wenkuSql, PreparedStatement.RETURN_GENERATED_KEYS);
                    pstmt.setString(1, title);
                    pstmt.setInt(2, userId);
                    pstmt.setString(3, documentType);
                    pstmt.setInt(4, fileId);
                    pstmt.setBigDecimal(5, priceValue);
                    pstmt.setInt(6, typeId);
                    pstmt.setLong(7, currentTime);
                    pstmt.setLong(8, currentTime);
                    pstmt.setInt(9, 1);
                    
                    int wenkuRowsAffected = pstmt.executeUpdate();
                    logger.info("文档信息已保存到wk_wenku表，影响行数: {}", wenkuRowsAffected);
                    
                    // 获取wen_id
                    try (java.sql.ResultSet generatedKeys = pstmt.getGeneratedKeys()) {
                        if (generatedKeys.next()) {
                            wenId = generatedKeys.getInt(1);
                            logger.info("获取到文档ID: {}", wenId);
                        }
                    }
                }
            } catch (SQLException e) {
                logger.error("保存文件信息到数据库失败: {}", e.getMessage(), e);
                // 数据库错误不应阻止文件上传流程继续
            } finally {
                if (pstmt != null) {
                    try { pstmt.close(); } catch (SQLException e) {}
                }
                DatabaseUtil.closeConnection(conn);
            }
            
            // 5. 调用图片解析API
            String analyzeResult = callImageAnalyzeApi(savedFilePath, newFileName, wenId);
            logger.info("图片解析API调用结果: {}", analyzeResult);
            
            // 6. 返回成功响应
            resultJson = "{\"code\":0,\"message\":\"上传成功\",\"data\":{\"fileName\":\"" + fileName
                    + "\",\"documentType\":\"" + documentType + "\"";
            
            if ("pay".equals(documentType)) {
                resultJson += ",\"price\":\"" + price + "\"";
            }
            
            // 在data中添加wenId信息
            resultJson += ",\"wenId\":" + wenId + "}}";
            
        } catch (Exception e) {
            logger.error("文件上传过程中发生异常: {}", e.getMessage(), e);
            resultJson = "{\"code\":4,\"message\":\"服务器内部错误\"}";
        }
        
        return resultJson;
    }
    
    public void destroy() {
        // 清理资源
    }
}